package tjs.study.notes.dotest.jvm.step;

import javassist.CannotCompileException;
import tjs.study.notes.dotest.TjsStudyNotesApplication;

import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by Nicky.Tang on 2021/10/22 10:13 下午
 *
 * @since 02.12.10
 */
public class 验证变量位置 {

    static List<Object> list = new ArrayList<>(99999);//保存到集合中，避免被释放了

//    static char[] chars = new char[1024*1024*4];
    static final char[] charsFinal = new char[1024*1024*4];


    /**
     * -XX:+PrintGCDetails  -Xms3m -Xmx3m -XX:MetaspaceSize=9M  -XX:MaxMetaspaceSize=9M
     *
     */
    public static void main(String[] args)  {
//        testHeapOom();
//        testPermGenOom();
            testStrPoolOom();

    }

    // 测试堆
    public static void testHeapOom() throws Exception {
        doTest(() -> {
            list.add(new byte[1024 * 1024]);
        });
    }

    /**
     * 测试方法区
     * jdk1.6/1.7   堆上的永久代中      OutOfMemoryError: PermGen space
     * jdk1.8       堆外的元空间        OutOfMemoryError:Metaspace
     * @throws Exception
     */
    public static void testPermGenOom() throws Exception {
        URL[] urls = {new File(TjsStudyNotesApplication.work_space_classes).toURI().toURL()};
        doTest(() -> {
            ClassLoader classLoader = new URLClassLoader(urls);
            list.add(classLoader);
            Class<?> classStatic = classLoader.loadClass("tjs.study.notes.dotest.jvm.step.StaticParent");
            classStatic.newInstance();
        });
    }

    // 测试元空间
    public static void testMetaspaceOom() throws Exception {
        testPermGenOom();
    }

    //
    //

    /**
     * str.intern(),不断运行，最终抛出异常，是抛出的StringBuilder/String里面的char数组动态扩容导致的堆OOM，扩容时都还没调用.intern()方法呢，所以此demo无法验证字符串常量池存在堆中
     * 但是反向推理，为什么扩容时会报堆不够用，还不是因为前面已经生成的字符串放到了堆上，所以新的字符串就不够放了
     *
     * jdk1.6          堆上的永久代
     * jdk1.7/jdk1.8   堆上字符串常量池
     */
    public static void testStrPoolOom() {
        long i = 88888888;
        try {
            for (; i >0 ; i++) {
                char[] chars = new char[]{'a','b','c','d', (char) i};
                list.add(String.valueOf(chars).intern());
            }
        } catch (Throwable ex) {
            ex.printStackTrace();
            System.out.println("i: " + i);
        }
    }

    interface TestBody {
        void doTest() throws Exception;
    }

    public static void doTest(TestBody testBody) throws Exception {
        int i = 0;
        try {
            while (true) {
                testBody.doTest();
                i++;
                System.out.println(i);
            }
        } catch (Exception ex) {
            ex.printStackTrace();
            System.out.println("i: " + i);
        }
    }

    static class ObjectHand {

    }

    static class Test {
        static ObjectHand objectHand = new ObjectHand();//方法区（jdk8,堆中）
        ObjectHand objectHand2 = new ObjectHand();//堆

        public Test() {
            ObjectHand objectHand3 = new ObjectHand();//栈帧-局部变量表
        }
    }
}
